package emulator.GUI.io;

import javax.swing.BorderFactory;
import javax.swing.GroupLayout;
import javax.swing.GroupLayout.Alignment;
import javax.swing.GroupLayout.ParallelGroup;
import javax.swing.GroupLayout.SequentialGroup;
import javax.swing.ImageIcon;
import javax.swing.JLabel;
import javax.swing.JPanel;

import emulator.hardware.io.Port6522;

@SuppressWarnings("serial")
public class PortPanel extends JPanel
{
	private static ImageIcon disabledOff = new ImageIcon("images/red-off-16.png");
	private static ImageIcon disabledOn = new ImageIcon("images/green-off-16.png");
	private static ImageIcon enabledOff = new ImageIcon("images/red-on-16.png");
	private static ImageIcon enabledOn = new ImageIcon("images/green-on-16.png");
	
	private static ImageIcon fallingEdgeIn = new ImageIcon("images/falling-edge-in.png");
	private static ImageIcon fallingEdgeInR = new ImageIcon("images/falling-edge-in-r.png");
	private static ImageIcon risingEdgeIn = new ImageIcon("images/rising-edge-in.png");
	private static ImageIcon risingEdgeInR = new ImageIcon("images/rising-edge-in-r.png");
	private static ImageIcon handshakeOut = new ImageIcon("images/handshake-out.png");
	private static ImageIcon pulseOut = new ImageIcon("images/pulse-out.png");
	private static ImageIcon lowOut = new ImageIcon("images/low-out.png");
	private static ImageIcon highOut = new ImageIcon("images/high-out.png");
	
	private static String [] modeTips1 = new String [] {
		"Negative active edge",
		"Positive active edge"
	};
	private static String [] modeTips2 = new String [] {
		"Input negative active edge",
		"Independent interrupt input negative edge",
		"Input positive active edge",
		"Independent interrupt input positive edge",
		"Handshake output",
		"Pulse output",
		"Low output",
		"High output"
	};

	
	ImageIcon [] modeIcons1 = new ImageIcon [] { fallingEdgeIn, risingEdgeIn };
	ImageIcon [] modeIcons2 = new ImageIcon [] {
			fallingEdgeInR, fallingEdgeIn, risingEdgeInR, risingEdgeIn,
			handshakeOut, pulseOut, lowOut, highOut
	};
	
	JLabel [] portLabel = new JLabel [8];
	JLabel [] portIn = new JLabel [8]; 
	JLabel [] portOut = new JLabel [8]; 
	
	JLabel c1state = new JLabel(enabledOff);
	JLabel c1mode = new JLabel(fallingEdgeIn);
	JLabel c2state = new JLabel(enabledOff);
	JLabel c2mode = new JLabel(fallingEdgeInR);
	
	public PortPanel(String portName)
	{
		super();
		initPanel(portName);
	}

	private void initPanel(String portName)
	{
		setBorder(BorderFactory.createTitledBorder("Port "+portName));
		
		JLabel labelIn = new JLabel("In");
		JLabel labelOut = new JLabel("Out");
		
		for (int i = 0; i < 8; i++)
		{
			portLabel[i] = new JLabel("P"+portName+i);
			add(portLabel[i]);
			portIn[i] = new JLabel(disabledOff);
			add(portIn[i]);
			portOut[i] = new JLabel(disabledOff);
			add(portOut[i]);
		}
		
		JLabel c1Label = new JLabel("C"+portName+"1");
		JLabel c2Label = new JLabel("C"+portName+"2");
		
		GroupLayout layout = new GroupLayout(this);
		setLayout(layout);
		
		layout.setAutoCreateGaps(true);
		layout.setAutoCreateContainerGaps(true);

		SequentialGroup horGroup = layout.createSequentialGroup();
		SequentialGroup verGroup = layout.createSequentialGroup();
		
		ParallelGroup col0 = layout.createParallelGroup(Alignment.CENTER);
		ParallelGroup col1 = layout.createParallelGroup(Alignment.CENTER);
		ParallelGroup col2 = layout.createParallelGroup(Alignment.CENTER);

		col1.addComponent(labelIn);
		col2.addComponent(labelOut);
		
		verGroup.addGroup(layout.createParallelGroup(Alignment.CENTER).addComponent(labelIn).addComponent(labelOut));
		
		for (int i = 0; i < 8; i++)
		{
			verGroup.addGroup(
					layout.createParallelGroup(Alignment.CENTER)
						.addComponent(portLabel[i])
						.addComponent(portIn[i])
						.addComponent(portOut[i])
					);
			col0.addComponent(portLabel[i]);
			col1.addComponent(portIn[i]);
			col2.addComponent(portOut[i]);
		}
		
		col0.addGap(5);
		col1.addGap(5);
		col2.addGap(5);
		verGroup.addGap(5);
		
		col0.addComponent(c1Label);
		col1.addComponent(c1state);
		col2.addComponent(c1mode);
		verGroup.addGroup(
				layout.createParallelGroup(Alignment.CENTER)
					.addComponent(c1Label)
					.addComponent(c1state)
					.addComponent(c1mode)
				);
		
		col0.addComponent(c2Label);
		col1.addComponent(c2state);
		col2.addComponent(c2mode);
		verGroup.addGroup(
				layout.createParallelGroup(Alignment.CENTER)
					.addComponent(c2Label)
					.addComponent(c2state)
					.addComponent(c2mode)
				);
		
		horGroup
			.addGroup(col0)
			.addGroup(col1)
			.addGroup(col2);
		layout.setHorizontalGroup(horGroup);
		layout.setVerticalGroup(verGroup);
	}

	public void setPortStatus(Port6522 port)
	{
		int mask = port.getPortMask();
		for (int i = 0; i < 8; i++)
		{
			boolean isOut = (mask & (1 << i)) != 0;
			if (port.getInPortBit(i).getValue())
				portIn[i].setIcon(isOut ? disabledOn : enabledOn);
			else
				portIn[i].setIcon(isOut ? disabledOff : enabledOff);
			if (port.getOutPortBit(i).getValue())
				portOut[i].setIcon(isOut ? enabledOn : disabledOn);
			else
				portOut[i].setIcon(isOut ? enabledOff : disabledOff);
		}
		c1state.setIcon(port.getControlBit(0).getValue() ? enabledOn : enabledOff);
		c2state.setIcon(port.getControlBit(1).getValue() ? enabledOn : enabledOff);
	}

	public void setPortControlModes(int mode1, int mode2)
	{
		c1mode.setIcon(modeIcons1[mode1]);
		c1mode.setToolTipText(modeTips1[mode1]);
		c2mode.setIcon(modeIcons2[mode2]);
		c2mode.setToolTipText(modeTips2[mode2]);
	}
}
